import { Injectable } from '@nestjs/common';
import { DictType } from './entities/dict-type.entity';
import { DictItem } from './entities/dict-item.entity';
import {
  DataSource,
  FindManyOptions,
  FindOptionsWhere,
  In,
  Not,
  Repository,
} from 'typeorm';
import { SaveDictTypeDto } from './dto/dict-type.dto';
import { SaveDictItemDto } from './dto/dict-item.dto';

@Injectable()
export class DictService {
  private readonly dictTypeRepository: Repository<DictType>;
  private readonly dictItemRepository: Repository<DictItem>;
  constructor(private readonly dataSource: DataSource) {
    this.dictTypeRepository = this.dataSource.getRepository(DictType);
    this.dictItemRepository = this.dataSource.getRepository(DictItem);
  }

  async dictTypeExist(where: FindOptionsWhere<DictType>) {
    return await this.dictTypeRepository.existsBy(where);
  }

  async saveDictType(saveDto: SaveDictTypeDto) {
    const exist = await this.dictTypeExist({
      code: saveDto.code,
      id: saveDto?.id ? Not(saveDto.id) : undefined,
    });
    if (exist) {
      throw new Error('dict.typeExist');
    }
    return await this.dictTypeRepository.save(
      this.dictTypeRepository.create(saveDto),
    );
  }

  async softDeleteDictType(ids: string[]) {
    const dictItems = await this.dictItemRepository.findBy({ typeId: In(ids) });
    if (dictItems.length) {
      await this.dictItemRepository.softDelete(dictItems.map((r) => r.id));
    }
    return await this.dictTypeRepository.softDelete(ids);
  }

  async findAndCountDictType(options: FindManyOptions<DictType>) {
    const [rows, total] = await this.dictTypeRepository.findAndCount(options);
    return {
      rows,
      total,
    };
  }

  async findDictType(filterKey: string = '') {
    return await this.dictTypeRepository.findOne({
      where: [
        {
          id: filterKey,
        },
        {
          code: filterKey,
        },
      ],
      relations: {
        items: true,
      },
    });
  }

  /** dictItem */

  async saveDictItem(saveDto: SaveDictItemDto) {
    const typeIsExist = await this.dictTypeExist({
      id: saveDto.typeId,
    });
    if (!typeIsExist) {
      throw new Error('dict.typeNotExist');
    }
    const exist = await this.dictItemRepository.existsBy({
      typeId: saveDto.typeId,
      value: saveDto.value,
      id: saveDto?.id ? Not(saveDto.id) : undefined,
    });
    if (exist) {
      throw new Error('dict.itemExist');
    }
    return await this.dictItemRepository.save(
      this.dictItemRepository.create(saveDto),
    );
  }

  async softDeleteDictItem(ids: string[]) {
    return await this.dictItemRepository.softDelete(ids);
  }

  async findDictTtems(options: FindManyOptions<DictItem>) {
    return await this.dictItemRepository.find(options);
  }

  async findItemsByTypeIdOrCode(filterKey: string) {
    const dictType = await this.findDictType(filterKey);
    return dictType?.items ?? [];
  }
}
